#ifndef PRAND_TOOL_H
#define PRAND_TOOL_H
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef struct {
	char *record;
	long size;
	long current;
	long last;
} randArr;

// seperate operations on randArr;
randArr* createRandArr(long maxvalue);
long getNextRand(randArr *ra);
void releaseRandArr(randArr *ra);
// generate a list in buffer, and buffer was previously allocated
void randPerm(long size, long start, long *buffer);

static long myrand(long maxvalue, long lastvalue)  {
	unsigned long v0 = rand() % 256;
	unsigned long v1 = rand() % 256;
	unsigned long v2 = rand() % 256;
	unsigned long v3 = rand() % 256;
	unsigned long v = (v3 << 24) + (v2 << 16) + (v1 << 8) + v0;
	return (v+lastvalue) % maxvalue;
}

randArr* createRandArr(long maxvalue) {
	char *s = (char*) malloc(maxvalue*sizeof(char));
	randArr* ra = (randArr*) malloc(sizeof(randArr));
	assert(maxvalue > 0);
	assert(s != NULL);
	assert(ra != NULL);
	if (s)
		memset(s, 0, sizeof(char)*maxvalue);
	if (ra) {
		ra->record = s;
		ra->size = maxvalue;
		ra->current = 0;
		ra->last = 0;
	}
	return ra;
}

void releaseRandArr(randArr* ra) {
	if (ra -> record) {
		free(ra->record);
		ra->record = NULL;
	}
	free(ra);
}

long getNextRand(randArr *ra) {
	long v;
	// return the index
	if (ra->current >= ra->size)
		return -1;
	v = myrand(ra->size, ra->last);
	while (ra->record[v] > 0)
		v = myrand(ra->size, ra->last);
	ra->record[v] = 1;
	ra->last = v % ra->size;
	ra->current++;
	return ra->last;
}

void randPerm(long size, long start, long *buffer) {
	randArr *ra = NULL;
	long i;
	srand(start);
	ra = createRandArr(size);
	for (i = 0;i < size;i++) {
		buffer[i] = getNextRand(ra);
	}
	releaseRandArr(ra);
}

#endif